/**
 * File:   GrilleMotsCroises.hpp
 * Author: CHABOT DIEP MYCEK
 *
 */

#ifndef _GRILLEMOTSCROISES_HPP
#define	_GRILLEMOTSCROISES_HPP

#include "Grille.hpp"
#include "Mot.hpp"
#include "Ihm.hpp"

using namespace std;

/**
 \class GrilleMotsCroises
 \brief Gestion du type GrilleMotsCroises
 Attributs
 - nbCasesNoires : un entier
 - nbMotsH : un entier (nombre de mots horizontaux)
 - nbMotsV : un entier (nombre de mots verticaux)
 - ini : un booleen (sert a savoir si la grille tabCases a ete initialisee ou non)
 - iniMot : un booleen (sert a savoir si la grille tabMots a ete initialisee ou non)
 - *tabMots : un tableau de Mot
 - **tabCases : un tableau a double entree de CaseMotsCroises
 - ihm : un objet de type Ihm
 */
class GrilleMotsCroises : public Grille{
private :
    int nbCasesNoires;
    int nbMotsH, nbMotsV;
    bool ini, iniMot;
    Mot *tabMots;
    CaseMotsCroises **tabCases;
    Ihm ihm;

public :
	/**
	\fn GrilleMotsCroises()
	\brief constructeur par defaut de GrilleMotsCroises. Sert en mode joueur ou edition car on ne peut pas connaitre les dimensions tant qu'on n'a pas charge la grille (il faut cependant avoir cree la grille pour pouvoir appeler sa methode charger).
	*/
	GrilleMotsCroises();
	
 	/**
     *\fn GrilleMotsCroises(int lg, int haut, int pourcentage);
     *\brief constructeur de GrilleMotsCroises. Sert en mode generation de grille car on peut definir les dimensions (desirs de l'utilisateur) 
     *\param lg un entier (le nombre de cases horizontales de la grille)
     *\param haut un entier (le nombre de cases verticales de la grille)
     *\param pourcentage un entier (pourcentage maximal de cases noires dans la grille)
     */
	GrilleMotsCroises(int lg, int haut, int pourcentage);
	
	/**
	\fn GrilleMotsCroises(const GrilleMotsCroises& grille)
	\brief constructeur par recopie de GrilleMotsCroises. Sert en mode joueur pour copier la grille utilisee avec ou sans les mots apparaissant dedans.
	\param grille une GrilleMotsCroises constante passee par reference
	\param remplir un booleen egal a true s'il faut remplir la grille, a false sinon.
	*/
	GrilleMotsCroises(const GrilleMotsCroises& grille, bool remplir);
	
	/**
	*\fn ~GrilleMotsCroises
	*\brief destructeur de GrilleMotsCroises
	*/
	~GrilleMotsCroises();
	
	/**
     *\fn bool init()
     *\brief permet d'initialiser la grille. Elle est appelee apres le constructeur avec arguments en mode generation.
     *\return TRUE si la procédure s'est terminée normalement.
     */
	bool init();
	
	/**
     \fn void init(int lg, int haut, int nbM)
     \brief permet d'initialiser la grille. Elle est appelee apres le constructeur sans arguments (par defaut) en mode joueur.
     \param lg la longueur de la grille (entier)
     \param haut la hauteur de la grille (entier)
     \param nbM le nombre de mots dans la grille (entier)
     \return void
     */
	void init(int lg, int haut, int nbM);
	
	/**
	\fn void initCasesNoires(int lg, int haut)
	\brief place les cases noires (mode generation)
	\param lg la longueur de la grille (entier)
	\param haut la hauteur de la grille (entier)
	\return void
	*/
	void initCasesNoires(int lg, int haut);
	
	/**
	\fn verifieContraintes(int x, int y)
	\brief retourne true si on peut ajouter une case noire a cet emplacement
	\param x l'indice de ligne
	\param y l'indice de colonne
	*/
	bool verifieContraintes(int x, int y);
	
	/**
	\fn creeVide(int x, int y)
	\brief retourne true si on peut ajouter une case noire a cet emplacement sans creer de case "isolee"
	\param x l'indice de ligne
	\param y l'indice de colonne
	*/
	bool creeVide(int x, int y);
	
	/**
	\fn bool testEcarts(int lg, int haut)
	\brief une fois les cases noires placees, permet de trouver les suite de cases vides de plus de 15 cases. Si un tel cas de figure existe, on appelle minEcarts, on supprime la case noire retournee, et on ajoute une case noire au milieu de la suite de cases vides pour la partager en deux suites de cases de longueur inferieure a 15.
	\param lg la longueur de la grille (entier)
	\param haut la hauteur de la grille (entier)
	return void
	*/
	void testEcarts(int lg, int haut);
	
	/**
	\fn void testMotsLongs(int lg, int haut)
	\param lg la longueur de la grille (entier)
	\param haut la hauteur de la grille (entier)
	\brief teste si deux lignes ou deux colonnes successives ont plus de 10 cases adjacentes vides. Si c'est le cas, cette fonction appelle minEcarts pour ajouter une case noire
	\return void
	*/
    void testMotsLongs(int lg, int haut);
	
	/**
	\fn void minEcarts(int lg, int haut, int &indi, int &indj)
	\brief permet de trouver une case noire dont la suppression induit des longueurs minimales pour les nouvelles suites de cases vides ainsi generee en ligne et en colonne.
	\param lg la longueur de la grille (entier)
	\param haut la hauteur de la grille (entier)
	\param indi l'indice de ligne trouve (entier)
	\param indj l'indice de colonne trouve (entier)
	\return indi, indj
	*/
	void minEcarts(int lg, int haut, int &indi, int &indj);
	
    /**
     *\fn int ajouterMot(int x, int y, bool vertical, string mot)
     *\brief permet d'ajouter un mot dans la grille (c'est cette fonction qui remplit les cases du tableau de cases)
     *\param x un entier
     *\param y un entier
     *\param vertical un booleen
     *\param mot une chaine de caracteres
     *\return void
     */
  
    int ajouterMot(int x, int y, bool vertical, string mot);
    
    /**
    \fn int chargerMot(int num, int x, int y, bool vertical, string mot)
    \brief appelee par la fonction charger, permet de charger un mot d'une grille prealablement sauvegardee.
    \param num le numero du mot (dans tabMots) : entier
    \param x l'indice de ligne ou ajouter le mot : entier
    \param y l'indice de colonne ou ajouter le mot : entier
    \param vertical true si le mot est vertical, false sinon : booleen
    \param mot le mot a ajouter : une chaine de caracteres
    \return 0 s'il y a eu une erreur, 1 sinon.
    */
    int chargerMot(int num, int x, int y, bool vertical, string mot);
    
    /**
     \fn void enleverMot(Mot mot)
     \brief permet de supprimer un mot de la grille
     \param mot un Mot
     \return void
     */
    void enleverMot(Mot mot);
    
    /**
     *\fn void ajouterCaseNoire(int x, int y)
     *\brief permet d'ajouter une case noire dans la grille
     *\param x un entier (ligne de la matrice)
     *\param y un entier (colonne de la matrice)
     *\return void
     */
    void ajouterCaseNoire(int x, int y);
    
    /**
     *\fn void defMots()
     *\brief a partir des emplacement des cases noires, definit les emplacements correspondant a des mots dans la grille
     *\param lg la longueur de la grille
     *\param haut la hauteur de la grille
     *\return void
     */
    void defMots(int lg, int haut);
     
    /**
    \fn int sauver()
    \brief sauvegarde une grille dans un fichier .xml dans le dossier grille. Le nom du fichier est entre sans le .xml (extension ajoutee automatiquement). Cette fonction utilise la librairie tinyxml.h et ses dependances.
    \return 1 si succes, 0 si echec.
    */
    int sauver();
    
    /**
    \fn int charger()
    \brief permet de charger une grille prealablement sauvegardee. Cette fonction utilise la librairie tinyxml.h et ses dependances.
    \return 1 si succes, 0 si echec.
    */
    int charger();
    
    /**
    \fn void afficher(bool affMots)
    \brief affiche la grille
    \param affMots un booleen permettant de savoir si on affiche ou non les mots dans la grille (utile pour le mode joueur)
    \return void
    */
    void afficher(bool affMots);
	
	/**
	\fn void afficherDef()
	\brief affiche les definitions.
	\return void
	*/
    void afficherDef();
    
    /**
    \fn int proposerLettre(int x, int y, char c, bool forcer=false)
    \brief en mode joueur, permet de proposer une lettre a un emplacement.
    \param x indice de ligne ou ajouter la lettre : entier
    \param y indice de colonne ou ajouter la lettre : entier
    \param c la lettre a ajouter : caractere
    \param forcer egal a true si l'on veut forcer l'ecrasement d'une lettre eventuellement deja presente a l'emplacement souhaite (utile si appelee depuis la fonction proposerMot qui appelle proposerLettre autant de fois que le mot comporte de caracteres). forcer = false par defaut.
    \return 1 si succes, 0 si echec.
    */
    int proposerLettre(int x, int y, char c, bool forcer=false);
    
    /**
    \fn int proposerMot(int x, int y, const char* m, bool vert)
    \brief en mode joueur, permet de proposer un mot (ou plus exactement une chaine de caracteres) a un emplacement.
    \param x indice de ligne ou ajouter le mot : entier
    \param y indice de colonne ou ajouter le mot : entier
    \param m le mot que l'on souhaite ajouter : chaine de caractere constante
    \param vert un booleen egal a true si le mot est vertical, a false sinon.
    \return 1 si succes, 0 si echec.
    */
    int proposerMot(int x, int y, const char* m, bool vert);
    
    /**
    \fn bool estRemplie()
    \brief sert a savoir si la grille est remplie (travaille sur les cases de la grille)
    \return true si la grille est remplie, false sinon.
    */
    bool estRemplie();
    
    /**
    \fn bool estRemplieMots()
    \brief sert a savoir si la grille est remplie (travaille sur les mots)
    \return true si la grille est remplie, false sinon.
    */
    bool estRemplieMots();
    
    /**
    \fn char getContenu(int i, int j)
    \brief permet de retourner le contenu d'une case de tabCases
    \param i l'indice de ligne
    \param j l'indice de colonne
    \return le caractere de tabCases[i][j]
    */
    char getContenu(int i, int j);
    
    /**
    \fn void setContenu(int i, int j, char c)
    \brief permet de definir le contenu d'une case de tabCases
    \param i l'indice de ligne
    \param j l'indice de colonne
    \param c le caractere a placer dans tabCases[i][j]
    \return void
    */
    void setContenu(int i, int j, char c);
    
    /**
    \fn void editer()
    \brief permet d'editer les definitions
    \return void
    */
    void editer();
    
    /**
    \fn void reinitialiser()
    \brief efface les mots et les cases de la grille pour pouvoir recommencer un remplissage de la meme grille
    \return void
    */
    void reinitialiser();
    
    /**
    \fn void afficherTabMots()
    \brief affiche les mots de la grille
    \return void
    */
    void afficherTabMots();


    /**
    \fn bool generation()
    \brief  C'est la fonction appele pour generer une grille de mots croises. 
    \return Elle retourne true si la generation a fonctionne et false autrement. 
    */
    bool generation();
   /**
     \fn  void remplirMot(int numero, string motstr)
     \brief Cette fonction permet de remplir les cases de la grille avec un mot lors de la generation (gestion des cases et des mots). 
     \param numero : le numero du mot que l'on remplie (entier)
     \param motstr : le mot que l'on met dans la grille  (chaine de caractere)
      \return void
   */
    void remplirMot(int numero, string motstr);
    
    /**
    \fn bool eliminerPossibiliteList(int mot1,int mot2,int pos1,int pos2)
    \brief  On regarde quelles sont les lettres qui ne sont pas en commum dans les deux mots aux positions donnees puis on fait appel au fonction filtre de la classe Mot pour eliminer des possibilites. 
    \param mot1 : numero du premier mot (entier)
    \param mot2 : numero du second mot (entier))
    \param pos1 : position de la case commune dans le premier mot (entier)
    \param pos2 : position de la case commune dans le second mot (entier)
    \return true si on a appliquer un filtre, false sinon. 
    */
    bool eliminerPossibiliteList(int mot1,int mot2,int pos1,int pos2);
    
    /**
    \fn int filtrage()
    \brief Fonction qui va permettre de filtrer les possibilites parmi les mots encore possibles.
    \return Retourne le nombre de possibilites minimale parmi les mots qui ne sont pas rempli
    */
    
    int filtrage(); 
    /**
    \fn  bool testPossibilite(int numero, string motstr,bool copier)
    \brief Test si au coup d'apres le mot n'entrainera pas une impossibilite. 
    \param numero  le numero du mot que l'on test (entier)
    \param motstr le mot que l'on cherche a tester (chaine de caractere)
    \param copier Un booleen permettant de copier les resultats du filtrage dans les listes de travail (booleen)
    \return True si le mot laisse des possibilite, false s'il debouche sur une impasse
    */
    bool testPossibilite(int numero, string motstr,bool copier);
   
   /**
   \ bool enleverMot()
   \brief Fonction qui permet de trouver quel mot il faudrait le mieux enlever (apres calcul de possibilite pour chaque mot) et qui l'enleve
   \return true si on a effectivement enlever un mot
    */
    bool enleverMot();
    /**
     *\fn int calculMinPossibilites(double &nbPos)
     *\brief trouve le Mot pour lequel il y a le moins de possibilites de remplissage ( Le nombre de possibilite est ici pondere par le nombre de lettre du mot).   
     *\param nbPos  le nombre de possibilite du mot ayant le moins de possibilite (nombre reel en double precision)
     *\return le numero du mot ayant le moins de possibilite
     */
    int calculMinPossibilites(double &nbPos);
    
    
    /**
    \ double testEnlevage(int numero)
    \brief Fonction qui permet d'enlever virtuellement un mot rempli
    \param numero Le numero du mot a enlever virtuellement (entier)
    \return le nombre de possibilite du mot ayant le moins de possibilite ( au sens de la fonction precedente)
    */
    double testEnlevage(int numero);
    
    /**
    \fn maxChance(int numero,string &motstr)
    \brief fonction qui permet, pour un Mot donne de trouve quel mot du dictionnaire maximiserait ses possibilites
    \param numero Le numero du Mot pour lequel on cherche la meilleure solution (entier)
    \param motstr Le mot du dictionnaire qui maximiserait ses possibilites (chaine de caractere)
    \return true si on a trouve un mot, false sinon 
    */

    bool maxChance(int numero,string &motstr);
    /**
    \fn choisirMot(string &motstr,int numero)
    \brief Choisit un mot au hasard parmis tous ceux qui n'entraineront pas une impossibilite a l'etape suivante
    \param numero Le Numero du mot pour lequel on va devoir choisir un mot au hasard (entier)
    \param motstr Le mot choisit au hasard ( en enlevant certaine possibilite) (chaine de caracatere)
    \return true si on a reussi a trouver un mot, false sinon
    */
    bool choisirMot(string &motstr,int numero);
    /**
    \fn echoue()
    \brief Fonction qui test si l'un des fichiers associes a chaque mot est vide, ce qui signifierait que l'on a ecarte toutes les possibilites en les testant toutes
    \return true si tel est le cas, false sinon.
    */
    bool echoue();
    
    /**
    \fn int getNbMotsH()
    \return nbMotsH
    */
    int getNbMotsH();
    
    /**
    \fn int getNbMotsV()
    \return nbMotsV
    */
    int getNbMotsV();
};

#endif	/* _GRILLEMOTSCROISES_HPP */

